import os
import re
import tkinter as tk
from tkinter import filedialog, messagebox, ttk, simpledialog
import logging
import time

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    filename='batch_rename.log'
)

class BatchImageRenamer:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("灵活图片重命名工具")
        self.root.geometry("900x700")
        
        # 中文字体支持
        self.root.option_add("*Font", "SimHei 10")
        
        # 图片类型配置（支持单独选择）
        self.image_types = {
            "主图": {
                "prefix": "Main",
                "replace_chars": ["主", "图", "首"],
                "aliases": ["主图", "Main", "main", "主图文件夹"],
                "selected": tk.BooleanVar(value=True)  # 默认选中
            },
            "详情图": {
                "prefix": "Detail",
                "replace_chars": ["详情", "长图", "描述"],
                "aliases": ["详情图", "Detail", "detail", "详情文件夹"],
                "selected": tk.BooleanVar(value=False)  # 默认不选
            }
        }
        
        # 存储目标文件夹路径（支持直接选图片文件夹或上级目录）
        self.target_dir = ""
        # 存储待处理的图片文件夹（主图/详情图文件夹路径）
        self.image_folders = []
        
        self.create_widgets()
        
    def create_widgets(self):
        # ========== 1. 目录选择区 ==========
        dir_frame = tk.LabelFrame(self.root, text="选择处理范围")
        dir_frame.pack(fill=tk.X, padx=20, pady=10)
        
        # 选择目标目录（可直接是图片文件夹的上级目录，或单个图片文件夹）
        tk.Label(dir_frame, text="目标目录:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        
        self.dir_var = tk.StringVar(value="未选择目录")
        tk.Entry(dir_frame, textvariable=self.dir_var, width=50, state="readonly").grid(row=0, column=1, padx=5, pady=5)
        tk.Button(dir_frame, text="浏览...", command=self.select_target_dir).grid(row=0, column=2, padx=5, pady=5)
        
        # 扫描到的图片文件夹列表（自动识别主图/详情图文件夹）
        tk.Label(dir_frame, text="识别到的图片文件夹:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.NW)
        
        self.folder_listbox = tk.Listbox(dir_frame, width=60, height=3, selectmode=tk.MULTIPLE)
        self.folder_listbox.grid(row=1, column=1, padx=5, pady=5, sticky=tk.NSEW)
        
        # 刷新按钮
        tk.Button(dir_frame, text="刷新列表", command=self.refresh_image_folders).grid(row=1, column=2, padx=5, pady=5, sticky=tk.N)
        
        # ========== 2. 处理类型选择区 ==========
        type_frame = tk.LabelFrame(self.root, text="选择处理类型")
        type_frame.pack(fill=tk.X, padx=20, pady=10)
        
        # 用复选框支持单独选择主图/详情图
        for i, type_name in enumerate(self.image_types.keys()):
            cb = tk.Checkbutton(
                type_frame,
                text=type_name,
                variable=self.image_types[type_name]["selected"],
                command=self.refresh_image_folders  # 选择后自动刷新文件夹列表
            )
            cb.grid(row=0, column=i, padx=20, pady=10, sticky=tk.W)
        
        # 别名配置（可选，用于扩展识别范围）
        tk.Label(type_frame, text="别名配置（可选）:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        
        self.type_alias_var = tk.StringVar(value=list(self.image_types.keys())[0])
        tk.OptionMenu(type_frame, self.type_alias_var, *self.image_types.keys()).grid(row=1, column=1, padx=5, pady=5, sticky=tk.W)
        
        self.alias_entry = tk.Entry(type_frame, width=20)
        self.alias_entry.grid(row=1, column=2, padx=5, pady=5)
        
        tk.Button(type_frame, text="添加别名", command=self.add_alias).grid(row=1, column=3, padx=5, pady=5)
        
        # ========== 3. 执行区 ==========
        action_frame = tk.Frame(self.root)
        action_frame.pack(fill=tk.X, padx=20, pady=10)
        
        self.start_btn = tk.Button(
            action_frame,
            text="开始重命名",
            command=self.start_rename,
            bg="#4CAF50",
            fg="white",
            font=("SimHei", 11),
            width=15
        )
        self.start_btn.pack(side=tk.LEFT, padx=5)
        
        # 延时设置
        tk.Label(action_frame, text="操作延时(秒):").pack(side=tk.LEFT, padx=10)
        self.delay_var = tk.DoubleVar(value=0.1)
        tk.Scale(
            action_frame,
            from_=0,
            to=1,
            resolution=0.1,
            orient=tk.HORIZONTAL,
            variable=self.delay_var,
            length=150
        ).pack(side=tk.LEFT)
        
        # ========== 4. 进度与日志区 ==========
        # 进度条
        self.progress_var = tk.DoubleVar()
        self.progress_bar = ttk.Progressbar(self.root, variable=self.progress_var, length=600, mode='determinate')
        self.progress_bar.pack(padx=20, pady=5)
        
        self.progress_label = tk.Label(self.root, text="就绪", anchor=tk.W)
        self.progress_label.pack(padx=20, pady=2, fill=tk.X)
        
        # 日志区
        tk.Label(self.root, text="操作日志:").pack(anchor=tk.W, padx=20, pady=5)
        self.log_text = tk.Text(self.root, height=12, width=70)
        self.log_text.pack(padx=20, pady=5, fill=tk.BOTH, expand=True)
        
        scrollbar = tk.Scrollbar(self.log_text, command=self.log_text.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.log_text.config(yscrollcommand=scrollbar.set)
        
        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_bar = tk.Label(self.root, textvariable=self.status_var, bd=1, relief=tk.SUNKEN, anchor=tk.W)
        status_bar.pack(side=tk.BOTTOM, fill=tk.X)
    
    # ========== 核心功能：目录选择与识别 ==========
    def select_target_dir(self):
        """选择目标目录（支持两种场景：1. 一级目录；2. 单个二级目录；3. 直接是图片文件夹）"""
        self.target_dir = filedialog.askdirectory(title="选择目标目录（可是一级目录/二级目录/图片文件夹）")
        if self.target_dir:
            self.dir_var.set(self.target_dir)
            self.log(f"已选择目标目录: {self.target_dir}")
            self.refresh_image_folders()  # 自动识别图片文件夹
    
    def refresh_image_folders(self):
        """刷新识别到的图片文件夹（根据选中的类型和别名）"""
        self.folder_listbox.delete(0, tk.END)
        self.image_folders = []
        
        if not self.target_dir:
            return
        
        # 收集需要处理的类型（主图/详情图，根据复选框选择）
        selected_types = [t for t in self.image_types if self.image_types[t]["selected"].get()]
        if not selected_types:
            self.log("请至少选择一种图片类型（主图/详情图）")
            return
        
        # 递归扫描目标目录下的所有文件夹，识别符合条件的图片文件夹
        def scan_folder(current_dir):
            for item in os.listdir(current_dir):
                item_path = os.path.join(current_dir, item)
                if os.path.isdir(item_path):
                    # 检查是否匹配选中的类型别名
                    for type_name in selected_types:
                        if item in self.image_types[type_name]["aliases"]:
                            self.image_folders.append((item_path, type_name))
                            self.folder_listbox.insert(tk.END, f"[{type_name}] {item_path}")
                    # 继续递归子文件夹（支持嵌套结构）
                    scan_folder(item_path)
        
        # 开始扫描
        scan_folder(self.target_dir)
        self.log(f"已识别 {len(self.image_folders)} 个图片文件夹（{', '.join(selected_types)}）")
    
    # ========== 别名管理 ==========
    def add_alias(self):
        """为选中的类型添加别名（增强识别能力）"""
        type_name = self.type_alias_var.get()
        alias = self.alias_entry.get().strip()
        if not alias:
            messagebox.showwarning("提示", "请输入别名")
            return
        
        if alias not in self.image_types[type_name]["aliases"]:
            self.image_types[type_name]["aliases"].append(alias)
            self.log(f"已为 [{type_name}] 添加别名：{alias}")
            self.alias_entry.delete(0, tk.END)
            self.refresh_image_folders()  # 刷新文件夹列表
        else:
            messagebox.showinfo("提示", f"别名 [{alias}] 已存在")
    
    # ========== 重命名核心逻辑 ==========
    def start_rename(self):
        """执行重命名（支持选择部分文件夹或全部）"""
        # 获取选中的文件夹（默认全选）
        selected_indices = self.folder_listbox.curselection()
        if not selected_indices:
            # 全选逻辑
            selected_folders = self.image_folders
        else:
            selected_folders = [self.image_folders[i] for i in selected_indices]
        
        if not selected_folders:
            messagebox.showinfo("提示", "未选择图片文件夹")
            return
        
        # 统计总文件数
        total_files = 0
        for folder_path, _ in selected_folders:
            total_files += len(self.get_image_files(folder_path))
        
        if total_files == 0:
            messagebox.showinfo("提示", "选中的文件夹中没有图片文件")
            return
        
        # 开始重命名
        self.start_btn.config(state=tk.DISABLED)
        self.status_var.set("正在处理...")
        processed = 0
        delay = self.delay_var.get()
        
        self.log(f"开始重命名 {total_files} 个文件（延时 {delay} 秒）")
        
        for folder_path, type_name in selected_folders:
            type_config = self.image_types[type_name]
            prefix = type_config["prefix"]
            replace_chars = type_config["replace_chars"]
            
            self.log(f"\n处理 [{type_name}] 文件夹：{folder_path}")
            
            # 获取并排序图片文件
            image_files = self.get_image_files(folder_path)
            sorted_files = self.sort_files_by_number(image_files)
            
            # 逐个重命名
            for idx, old_name in enumerate(sorted_files, start=1):
                try:
                    old_path = os.path.join(folder_path, old_name)
                    file_ext = os.path.splitext(old_name)[1].lower()
                    
                    # 构建新文件名（前缀+序号）
                    new_name = f"{prefix}-{idx:03d}{file_ext}"
                    new_path = os.path.join(folder_path, new_name)
                    
                    # 执行重命名
                    os.rename(old_path, new_path)
                    self.log(f"重命名：{old_name} → {new_name}")
                    
                    # 更新进度
                    processed += 1
                    progress = (processed / total_files) * 100
                    self.progress_var.set(progress)
                    self.progress_label.config(text=f"已处理 {processed}/{total_files} 个文件（{int(progress)}%）")
                    self.root.update_idletasks()
                    
                    # 延时
                    if delay > 0:
                        time.sleep(delay)
                        
                except Exception as e:
                    self.log(f"重命名失败（{old_name}）：{str(e)}")
        
        # 处理完成
        self.progress_var.set(100)
        self.progress_label.config(text=f"处理完成！共处理 {processed}/{total_files} 个文件")
        self.status_var.set("处理完成")
        self.start_btn.config(state=tk.NORMAL)
        messagebox.showinfo("完成", f"重命名完成！\n成功处理 {processed} 个文件")
    
    # ========== 工具方法 ==========
    def get_image_files(self, folder_path):
        """获取文件夹下的所有图片文件（支持常见格式）"""
        image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp']
        return [
            f for f in os.listdir(folder_path)
            if os.path.isfile(os.path.join(folder_path, f))
            and os.path.splitext(f)[1].lower() in image_extensions
        ]
    
    def sort_files_by_number(self, files):
        """按文件名中的数字排序（确保序号正确）"""
        def extract_number(filename):
            match = re.search(r'\d+', filename)
            return int(match.group()) if match else 0
        return sorted(files, key=extract_number)
    
    def log(self, message):
        """输出日志到界面和文件"""
        self.log_text.insert(tk.END, f"[{time.strftime('%H:%M:%S')}] {message}\n")
        self.log_text.see(tk.END)
        logging.info(message)

if __name__ == "__main__":
    app = BatchImageRenamer()
    app.root.mainloop()